home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / light.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  51.0 KB  |  2,129 lines

  1. // light.c
  2.  
  3. #include "light.h"
  4. #ifdef _WIN32
  5. #ifdef _TTIMOBUILD
  6. #include "pakstuff.h"
  7. #else
  8. #include "../libs/pakstuff.h"
  9. #endif
  10. #endif
  11.  
  12.  
  13. #define    EXTRASCALE    2
  14.  
  15. typedef struct {
  16.     float        plane[4];
  17.     vec3_t        origin;
  18.     vec3_t        vectors[2];
  19.     shaderInfo_t    *si;
  20. } filter_t;
  21.  
  22. #define    MAX_FILTERS    1024
  23. filter_t    filters[MAX_FILTERS];
  24. int            numFilters;
  25.  
  26. extern char    source[1024];
  27.  
  28. qboolean    notrace;
  29. qboolean    patchshadows;
  30. qboolean    dump;
  31. qboolean    extra;
  32. qboolean    extraWide;
  33. qboolean    lightmapBorder;
  34.  
  35. qboolean    noSurfaces;
  36.  
  37. int            samplesize = 16;        //sample size in units
  38. int            novertexlighting = 0;
  39. int            nogridlighting = 0;
  40.  
  41. // for run time tweaking of all area sources in the level
  42. float        areaScale =    0.25;
  43.  
  44. // for run time tweaking of all point sources in the level
  45. float        pointScale = 7500;
  46.  
  47. qboolean    exactPointToPolygon = qtrue;
  48.  
  49. float        formFactorValueScale = 3;
  50.  
  51. float        linearScale = 1.0 / 8000;
  52.  
  53. light_t        *lights;
  54. int            numPointLights;
  55. int            numAreaLights;
  56.  
  57. FILE        *dumpFile;
  58.  
  59. int            c_visible, c_occluded;
  60.  
  61. //int            defaultLightSubdivide = 128;        // vary by surface size?
  62. int            defaultLightSubdivide = 999;        // vary by surface size?
  63.  
  64. vec3_t        ambientColor;
  65.  
  66. vec3_t        surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
  67. int            entitySurface[ MAX_MAP_DRAW_SURFS ];
  68.  
  69. // 7,9,11 normalized to avoid being nearly coplanar with common faces
  70. //vec3_t        sunDirection = { 0.441835, 0.56807, 0.694313 };
  71. //vec3_t        sunDirection = { 0.45, 0, 0.9 };
  72. //vec3_t        sunDirection = { 0, 0, 1 };
  73.  
  74. // these are usually overrided by shader values
  75. vec3_t        sunDirection = { 0.45, 0.3, 0.9 };
  76. vec3_t        sunLight = { 100, 100, 50 };
  77.  
  78.  
  79.  
  80. typedef struct {
  81.     dbrush_t    *b;
  82.     vec3_t        bounds[2];
  83. } skyBrush_t;
  84.  
  85. int            numSkyBrushes;
  86. skyBrush_t    skyBrushes[MAX_MAP_BRUSHES];
  87.  
  88.  
  89. /*
  90.  
  91. the corners of a patch mesh will always be exactly at lightmap samples.
  92. The dimensions of the lightmap will be equal to the average length of the control
  93. mesh in each dimension divided by 2.
  94. The lightmap sample points should correspond to the chosen subdivision points.
  95.  
  96. */
  97.  
  98. /*
  99. ===============================================================
  100.  
  101. SURFACE LOADING
  102.  
  103. ===============================================================
  104. */
  105.  
  106. #define    MAX_FACE_POINTS        128
  107.  
  108. /*
  109. ===============
  110. SubdivideAreaLight
  111.  
  112. Subdivide area lights that are very large
  113. A light that is subdivided will never backsplash, avoiding weird pools of light near edges
  114. ===============
  115. */
  116. void SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal, 
  117.                         float areaSubdivide, qboolean backsplash ) {
  118.     float            area, value, intensity;
  119.     light_t            *dl, *dl2;
  120.     vec3_t            mins, maxs;
  121.     int                axis;
  122.     winding_t        *front, *back;
  123.     vec3_t            planeNormal;
  124.     float            planeDist;
  125.  
  126.     if ( !w ) {
  127.         return;
  128.     }
  129.  
  130.     WindingBounds( w, mins, maxs );
  131.  
  132.     // check for subdivision
  133.     for ( axis = 0 ; axis < 3 ; axis++ ) {
  134.         if ( maxs[axis] - mins[axis] > areaSubdivide ) {
  135.             VectorClear( planeNormal );
  136.             planeNormal[axis] = 1;
  137.             planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
  138.             ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
  139.             SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
  140.             SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
  141.             FreeWinding( w );
  142.             return;
  143.         }
  144.     }
  145.  
  146.     // create a light from this
  147.     area = WindingArea (w);
  148.     if ( area <= 0 || area > 20000000 ) {
  149.         return;
  150.     }
  151.  
  152.     numAreaLights++;
  153.     dl = malloc(sizeof(*dl));
  154.     memset (dl, 0, sizeof(*dl));
  155.     dl->next = lights;
  156.     lights = dl;
  157.     dl->type = emit_area;
  158.  
  159.     WindingCenter( w, dl->origin );
  160.     dl->w = w;
  161.     VectorCopy ( normal, dl->normal);
  162.     dl->dist = DotProduct( dl->origin, normal );
  163.  
  164.     value = ls->value;
  165.     intensity = value * area * areaScale;
  166.     VectorAdd( dl->origin, dl->normal, dl->origin );
  167.  
  168.     VectorCopy( ls->color, dl->color );
  169.  
  170.     dl->photons = intensity;
  171.  
  172.     // emitColor is irrespective of the area
  173.     VectorScale( ls->color, value*formFactorValueScale*areaScale, dl->emitColor );
  174.  
  175.     dl->si = ls;
  176.  
  177.     if ( ls->contents & CONTENTS_FOG ) {
  178.         dl->twosided = qtrue;
  179.     }
  180.  
  181.     // optionally create a point backsplash light
  182.     if ( backsplash && ls->backsplashFraction > 0 ) {
  183.         dl2 = malloc(sizeof(*dl));
  184.         memset (dl2, 0, sizeof(*dl2));
  185.         dl2->next = lights;
  186.         lights = dl2;
  187.         dl2->type = emit_point;
  188.  
  189.         VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
  190.  
  191.         VectorCopy( ls->color, dl2->color );
  192.  
  193.         dl2->photons = dl->photons * ls->backsplashFraction;
  194.         dl2->si = ls;
  195.     }
  196. }
  197.  
  198.  
  199. /*
  200. ===============
  201. CountLightmaps
  202. ===============
  203. */
  204. void CountLightmaps( void ) {
  205.     int            count;
  206.     int            i;
  207.     dsurface_t    *ds;
  208.  
  209.     qprintf ("--- CountLightmaps ---\n");
  210.     count = 0;
  211.     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
  212.         // see if this surface is light emiting
  213.         ds = &drawSurfaces[i];
  214.         if ( ds->lightmapNum > count ) {
  215.             count = ds->lightmapNum;
  216.         }
  217.     }
  218.  
  219.     count++;
  220.     numLightBytes = count * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3;
  221.     if ( numLightBytes > MAX_MAP_LIGHTING ) {
  222.         Error("MAX_MAP_LIGHTING exceeded");
  223.     }
  224.  
  225.     qprintf( "%5i drawSurfaces\n", numDrawSurfaces );
  226.     qprintf( "%5i lightmaps\n", count );
  227. }
  228.  
  229. /*
  230. ===============
  231. CreateSurfaceLights
  232.  
  233. This creates area lights
  234. ===============
  235. */
  236. void CreateSurfaceLights( void ) {
  237.     int                i, j, side;
  238.     dsurface_t        *ds;
  239.     shaderInfo_t    *ls;
  240.     winding_t        *w;
  241.     cFacet_t        *f;
  242.     light_t            *dl;
  243.     vec3_t            origin;
  244.     drawVert_t        *dv;
  245.     int                c_lightSurfaces;
  246.     float            lightSubdivide;
  247.     vec3_t            normal;
  248.  
  249.     qprintf ("--- CreateSurfaceLights ---\n");
  250.     c_lightSurfaces = 0;
  251.  
  252.     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
  253.         // see if this surface is light emiting
  254.         ds = &drawSurfaces[i];
  255.  
  256.         ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
  257.         if ( ls->value == 0 ) {
  258.             continue;
  259.         }
  260.  
  261.         // determine how much we need to chop up the surface
  262.         if ( ls->lightSubdivide ) {
  263.             lightSubdivide = ls->lightSubdivide;
  264.         } else {
  265.             lightSubdivide = defaultLightSubdivide;
  266.         }
  267.  
  268.         c_lightSurfaces++;
  269.  
  270.         // an autosprite shader will become
  271.         // a point light instead of an area light
  272.         if ( ls->autosprite ) {
  273.             // autosprite geometry should only have four vertexes
  274.             if ( surfaceTest[i] ) {
  275.                 // curve or misc_model
  276.                 f = surfaceTest[i]->facets;
  277.                 if ( surfaceTest[i]->numFacets != 1 || f->numBoundaries != 4 ) {
  278.                     _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
  279.                         (int)f->points[0], (int)f->points[1], (int)f->points[2] );
  280.                 }
  281.                 VectorAdd( f->points[0], f->points[1], origin );
  282.                 VectorAdd( f->points[2], origin, origin );
  283.                 VectorAdd( f->points[3], origin, origin );
  284.                 VectorScale( origin, 0.25, origin );
  285.             } else {
  286.                 // normal polygon
  287.                 dv = &drawVerts[ ds->firstVert ];
  288.                 if ( ds->numVerts != 4 ) {
  289.                     _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
  290.                         (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
  291.                     continue;
  292.                 }
  293.  
  294.                 VectorAdd( dv[0].xyz, dv[1].xyz, origin );
  295.                 VectorAdd( dv[2].xyz, origin, origin );
  296.                 VectorAdd( dv[3].xyz, origin, origin );
  297.                 VectorScale( origin, 0.25, origin );
  298.             }
  299.  
  300.  
  301.             numPointLights++;
  302.             dl = malloc(sizeof(*dl));
  303.             memset (dl, 0, sizeof(*dl));
  304.             dl->next = lights;
  305.             lights = dl;
  306.  
  307.             VectorCopy( origin, dl->origin );
  308.             VectorCopy( ls->color, dl->color );
  309.             dl->photons = ls->value * pointScale;
  310.             dl->type = emit_point;
  311.             continue;
  312.         }
  313.  
  314.         // possibly create for both sides of the polygon
  315.         for ( side = 0 ; side <= ls->twoSided ; side++ ) {
  316.             // create area lights
  317.             if ( surfaceTest[i] ) {
  318.                 // curve or misc_model
  319.                 for ( j = 0 ; j < surfaceTest[i]->numFacets ; j++ ) {
  320.                     f = surfaceTest[i]->facets + j;
  321.                     w = AllocWinding( f->numBoundaries );
  322.                     w->numpoints = f->numBoundaries;
  323.                     memcpy( w->p, f->points, f->numBoundaries * 12 );
  324.  
  325.                     VectorCopy( f->surface, normal );
  326.                     if ( side ) {
  327.                         winding_t    *t;
  328.  
  329.                         t = w;
  330.                         w = ReverseWinding( t );
  331.                         FreeWinding( t );
  332.                         VectorSubtract( vec3_origin, normal, normal );
  333.                     }
  334.                     SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
  335.                 }
  336.             } else {
  337.                 // normal polygon
  338.  
  339.                 w = AllocWinding( ds->numVerts );
  340.                 w->numpoints = ds->numVerts;
  341.                 for ( j = 0 ; j < ds->numVerts ; j++ ) {
  342.                     VectorCopy( drawVerts[ds->firstVert+j].xyz, w->p[j] );
  343.                 }
  344.                 VectorCopy( ds->lightmapVecs[2], normal );
  345.                 if ( side ) {
  346.                     winding_t    *t;
  347.  
  348.                     t = w;
  349.                     w = ReverseWinding( t );
  350.                     FreeWinding( t );
  351.                     VectorSubtract( vec3_origin, normal, normal );
  352.                 }
  353.                 SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
  354.             }
  355.         }
  356.     }
  357.  
  358.     _printf( "%5i light emitting surfaces\n", c_lightSurfaces );
  359. }
  360.  
  361.  
  362.  
  363. /*
  364. ================
  365. FindSkyBrushes
  366. ================
  367. */
  368. void FindSkyBrushes( void ) {
  369.     int                i, j;
  370.     dbrush_t        *b;
  371.     skyBrush_t        *sb;
  372.     shaderInfo_t    *si;
  373.     dbrushside_t    *s;
  374.  
  375.     // find the brushes
  376.     for ( i = 0 ; i < numbrushes ; i++ ) {
  377.         b = &dbrushes[i];
  378.         for ( j = 0 ; j < b->numSides ; j++ ) {
  379.             s = &dbrushsides[ b->firstSide + j ];
  380.             if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
  381.                 sb = &skyBrushes[ numSkyBrushes ];
  382.                 sb->b = b;
  383.                 sb->bounds[0][0] = -dplanes[ dbrushsides[ b->firstSide + 0 ].planeNum ].dist - 1;
  384.                 sb->bounds[1][0] = dplanes[ dbrushsides[ b->firstSide + 1 ].planeNum ].dist + 1;
  385.                 sb->bounds[0][1] = -dplanes[ dbrushsides[ b->firstSide + 2 ].planeNum ].dist - 1;
  386.                 sb->bounds[1][1] = dplanes[ dbrushsides[ b->firstSide + 3 ].planeNum ].dist + 1;
  387.                 sb->bounds[0][2] = -dplanes[ dbrushsides[ b->firstSide + 4 ].planeNum ].dist - 1;
  388.                 sb->bounds[1][2] = dplanes[ dbrushsides[ b->firstSide + 5 ].planeNum ].dist + 1;
  389.                 numSkyBrushes++;
  390.                 break;
  391.             }
  392.         }
  393.     }
  394.  
  395.     // default
  396.     VectorNormalize( sunDirection, sunDirection );
  397.  
  398.     // find the sky shader
  399.     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
  400.         si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
  401.         if ( si->surfaceFlags & SURF_SKY ) {
  402.             VectorCopy( si->sunLight, sunLight );
  403.             VectorCopy( si->sunDirection, sunDirection );
  404.             break;
  405.         }
  406.     }
  407. }
  408.  
  409. /*
  410. =================================================================
  411.  
  412.   LIGHT SETUP
  413.  
  414. =================================================================
  415. */
  416.  
  417. /*
  418. ==================
  419. FindTargetEntity
  420. ==================
  421. */
  422. entity_t *FindTargetEntity( const char *target ) {
  423.     int            i;
  424.     const char    *n;
  425.  
  426.     for ( i = 0 ; i < num_entities ; i++ ) {
  427.         n = ValueForKey (&entities[i], "targetname");
  428.         if ( !strcmp (n, target) ) {
  429.             return &entities[i];
  430.         }
  431.     }
  432.  
  433.     return NULL;
  434. }
  435.  
  436.  
  437.  
  438. /*
  439. =============
  440. CreateEntityLights
  441. =============
  442. */
  443. void CreateEntityLights (void)
  444. {
  445.     int        i;
  446.     light_t    *dl;
  447.     entity_t    *e, *e2;
  448.     const char    *name;
  449.     const char    *target;
  450.     vec3_t    dest;
  451.     const char    *_color;
  452.     float    intensity;
  453.     int        spawnflags;
  454.  
  455.     //
  456.     // entities
  457.     //
  458.     for ( i = 0 ; i < num_entities ; i++ ) {
  459.         e = &entities[i];
  460.         name = ValueForKey (e, "classname");
  461.         if (strncmp (name, "light", 5))
  462.             continue;
  463.  
  464.         numPointLights++;
  465.         dl = malloc(sizeof(*dl));
  466.         memset (dl, 0, sizeof(*dl));
  467.         dl->next = lights;
  468.         lights = dl;
  469.  
  470.         spawnflags = FloatForKey (e, "spawnflags");
  471.         if ( spawnflags & 1 ) {
  472.             dl->linearLight = qtrue;
  473.         }
  474.  
  475.         GetVectorForKey (e, "origin", dl->origin);
  476.         dl->style = FloatForKey (e, "_style");
  477.         if (!dl->style)
  478.             dl->style = FloatForKey (e, "style");
  479.         if (dl->style < 0)
  480.             dl->style = 0;
  481.  
  482.         intensity = FloatForKey (e, "light");
  483.         if (!intensity)
  484.             intensity = FloatForKey (e, "_light");
  485.         if (!intensity)
  486.             intensity = 300;
  487.         _color = ValueForKey (e, "_color");
  488.         if (_color && _color[0])
  489.         {
  490.             sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
  491.             ColorNormalize (dl->color, dl->color);
  492.         }
  493.         else
  494.             dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
  495.  
  496.         intensity = intensity * pointScale;
  497.         dl->photons = intensity;
  498.  
  499.         dl->type = emit_point;
  500.  
  501.         // lights with a target will be spotlights
  502.         target = ValueForKey (e, "target");
  503.  
  504.         if ( target[0] ) {
  505.             float    radius;
  506.             float    dist;
  507.  
  508.             e2 = FindTargetEntity (target);
  509.             if (!e2) {
  510.                 _printf ("WARNING: light at (%i %i %i) has missing target\n",
  511.                 (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
  512.             } else {
  513.                 GetVectorForKey (e2, "origin", dest);
  514.                 VectorSubtract (dest, dl->origin, dl->normal);
  515.                 dist = VectorNormalize (dl->normal, dl->normal);
  516.                 radius = FloatForKey (e, "radius");
  517.                 if ( !radius ) {
  518.                     radius = 64;
  519.                 }
  520.                 if ( !dist ) {
  521.                     dist = 64;
  522.                 }
  523.                 dl->radiusByDist = (radius + 16) / dist;
  524.                 dl->type = emit_spotlight;
  525.             }
  526.         }
  527.     }
  528. }
  529.  
  530. //=================================================================
  531.  
  532. /*
  533. ================
  534. SetEntityOrigins
  535.  
  536. Find the offset values for inline models
  537. ================
  538. */
  539. void SetEntityOrigins( void ) {
  540.     int            i, j;
  541.     entity_t    *e;
  542.     vec3_t        origin;
  543.     const char    *key;
  544.     int            modelnum;
  545.     dmodel_t    *dm;
  546.  
  547.     for ( i=0 ; i < num_entities ; i++ ) {
  548.         e = &entities[i];
  549.         key = ValueForKey (e, "model");
  550.         if ( key[0] != '*' ) {
  551.             continue;
  552.         }
  553.         modelnum = atoi( key + 1 );
  554.         dm = &dmodels[ modelnum ];
  555.  
  556.         // set entity surface to true for all surfaces for this model
  557.         for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
  558.             entitySurface[ dm->firstSurface + j ] = qtrue;
  559.         }
  560.  
  561.         key = ValueForKey (e, "origin");
  562.         if ( !key[0] ) {
  563.             continue;
  564.         }
  565.         GetVectorForKey ( e, "origin", origin );
  566.  
  567.         // set origin for all surfaces for this model
  568.         for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
  569.             VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] );
  570.         }
  571.     }
  572. }
  573.  
  574.  
  575. /*
  576. =================================================================
  577.  
  578.  
  579. =================================================================
  580. */
  581.  
  582. #define    MAX_POINTS_ON_WINDINGS    64
  583.  
  584. /*
  585. ================
  586. PointToPolygonFormFactor
  587. ================
  588. */
  589. float    PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) {
  590.     vec3_t        triVector, triNormal;
  591.     int            i, j;
  592.     vec3_t        dirs[MAX_POINTS_ON_WINDING];
  593.     float        total;
  594.     float        dot, angle, facing;
  595.  
  596.     for ( i = 0 ; i < w->numpoints ; i++ ) {
  597.         VectorSubtract( w->p[i], point, dirs[i] );
  598.         VectorNormalize( dirs[i], dirs[i] );
  599.     }
  600.  
  601.     // duplicate first vertex to avoid mod operation
  602.     VectorCopy( dirs[0], dirs[i] );
  603.  
  604.     total = 0;
  605.     for ( i = 0 ; i < w->numpoints ; i++ ) {
  606.         j = i+1;
  607.         dot = DotProduct( dirs[i], dirs[j] );
  608.  
  609.         // roundoff can cause slight creep, which gives an IND from acos
  610.         if ( dot > 1.0 ) {
  611.             dot = 1.0;
  612.         } else if ( dot < -1.0 ) {
  613.             dot = -1.0;
  614.         }
  615.         
  616.         angle = acos( dot );
  617.         CrossProduct( dirs[i], dirs[j], triVector );
  618.         if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) {
  619.             continue;
  620.         }
  621.         facing = DotProduct( normal, triNormal );
  622.         total += facing * angle;
  623.  
  624.         if ( total > 6.3 || total < -6.3 ) {
  625.             static qboolean printed;
  626.  
  627.             if ( !printed ) {
  628.                 printed = qtrue;
  629.                 _printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total,
  630.                     w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]);
  631.             }
  632.             return 0;
  633.         }
  634.  
  635.     }
  636.  
  637.     total /= 2*3.141592657;        // now in the range of 0 to 1 over the entire incoming hemisphere
  638.  
  639.     return total;
  640. }
  641.  
  642.  
  643. /*
  644. ================
  645. FilterTrace
  646.  
  647. Returns 0 to 1.0 filter fractions for the given trace
  648. ================
  649. */
  650. void    FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) {
  651.     float        d1, d2;
  652.     filter_t    *f;
  653.     int            filterNum;
  654.     vec3_t        point;
  655.     float        frac;
  656.     int            i;
  657.     float        s, t;
  658.     int            u, v;
  659.     int            x, y;
  660.     byte        *pixel;
  661.     float        radius;
  662.     float        len;
  663.     vec3_t        total;
  664.  
  665.     filter[0] = 1.0;
  666.     filter[1] = 1.0;
  667.     filter[2] = 1.0;
  668.  
  669.     for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) {
  670.         f = &filters[ filterNum ];
  671.  
  672.         // see if the plane is crossed
  673.         d1 = DotProduct( start, f->plane ) - f->plane[3];
  674.         d2 = DotProduct( end, f->plane ) - f->plane[3];
  675.  
  676.         if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
  677.             continue;
  678.         }
  679.  
  680.         // calculate the crossing point
  681.         frac = d1 / ( d1 - d2 );
  682.  
  683.         for ( i = 0 ; i < 3 ; i++ ) {
  684.             point[i] = start[i] + frac * ( end[i] - start[i] );
  685.         }
  686.  
  687.         VectorSubtract( point, f->origin, point );
  688.  
  689.         s = DotProduct( point, f->vectors[0] );
  690.         t = 1.0 - DotProduct( point, f->vectors[1] );
  691.         if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) {
  692.             continue;
  693.         }
  694.  
  695.         // decide the filter size
  696.         radius = 10 * frac;
  697.         len = VectorLength( f->vectors[0] );
  698.         if ( !len ) {
  699.             continue;
  700.         }
  701.         radius = radius * len * f->si->width;
  702.  
  703.         // look up the filter, taking multiple samples
  704.         VectorClear( total );
  705.         for ( u = -1 ; u <= 1 ; u++ ) {
  706.             for ( v = -1 ; v <=1 ; v++ ) {
  707.                 x = s * f->si->width + u * radius;
  708.                 if ( x < 0 ) {
  709.                     x = 0;
  710.                 }
  711.                 if ( x >= f->si->width ) {
  712.                     x = f->si->width - 1;
  713.                 }
  714.                 y = t * f->si->height + v * radius;
  715.                 if ( y < 0 ) {
  716.                     y = 0;
  717.                 }
  718.                 if ( y >= f->si->height ) {
  719.                     y = f->si->height - 1;
  720.                 }
  721.  
  722.                 pixel = f->si->pixels + ( y * f->si->width + x ) * 4;
  723.                 total[0] += pixel[0];
  724.                 total[1] += pixel[1];
  725.                 total[2] += pixel[2];
  726.             }
  727.         }
  728.  
  729.         filter[0] *= total[0]/(255.0*9);
  730.         filter[1] *= total[1]/(255.0*9);
  731.         filter[2] *= total[2]/(255.0*9);
  732.     }
  733.  
  734. }
  735.  
  736. /*
  737. ================
  738. SunToPoint
  739.  
  740. Returns an amount of light to add at the point
  741. ================
  742. */
  743. int        c_sunHit, c_sunMiss;
  744. void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) {
  745.     int            i;
  746.     trace_t        trace;
  747.     skyBrush_t    *b;
  748.     vec3_t        end;
  749.  
  750.     if ( !numSkyBrushes ) {
  751.         VectorClear( addLight );
  752.         return;
  753.     }
  754.  
  755.     VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end );
  756.  
  757.     TraceLine( origin, end, &trace, qtrue, tw );
  758.  
  759.     // see if trace.hit is inside a sky brush
  760.     for ( i = 0 ; i < numSkyBrushes ; i++) {
  761.         b = &skyBrushes[ i ];
  762.  
  763.         // this assumes that sky brushes are axial...
  764.         if (   trace.hit[0] < b->bounds[0][0] 
  765.             || trace.hit[0] > b->bounds[1][0]
  766.             || trace.hit[1] < b->bounds[0][1]
  767.             || trace.hit[1] > b->bounds[1][1]
  768.             || trace.hit[2] < b->bounds[0][2]
  769.             || trace.hit[2] > b->bounds[1][2] ) {
  770.             continue;
  771.         }
  772.  
  773.  
  774.         // trace again to get intermediate filters
  775.         TraceLine( origin, trace.hit, &trace, qtrue, tw );
  776.  
  777.         // we hit the sky, so add sunlight
  778.         if ( numthreads == 1 ) {
  779.             c_sunHit++;
  780.         }
  781.         addLight[0] = trace.filter[0] * sunLight[0];
  782.         addLight[1] = trace.filter[1] * sunLight[1];
  783.         addLight[2] = trace.filter[2] * sunLight[2];
  784.  
  785.         return;
  786.     }
  787.  
  788.     if ( numthreads == 1 ) {
  789.         c_sunMiss++;
  790.     }
  791.  
  792.     VectorClear( addLight );
  793. }
  794.  
  795. /*
  796. ================
  797. SunToPlane
  798. ================
  799. */
  800. void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) {
  801.     float        angle;
  802.     vec3_t        sunColor;
  803.  
  804.     if ( !numSkyBrushes ) {
  805.         return;
  806.     }
  807.  
  808.     angle = DotProduct( normal, sunDirection );
  809.     if ( angle <= 0 ) {
  810.         return;        // facing away
  811.     }
  812.  
  813.     SunToPoint( origin, tw, sunColor );
  814.     VectorMA( color, angle, sunColor, color );
  815. }
  816.  
  817. /*
  818. ================
  819. LightingAtSample
  820. ================
  821. */
  822. void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color, 
  823.                       qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) {
  824.     light_t        *light;
  825.     trace_t        trace;
  826.     float        angle;
  827.     float        add;
  828.     float        dist;
  829.     vec3_t        dir;
  830.  
  831.     VectorCopy( ambientColor, color );
  832.  
  833.     // trace to all the lights
  834.     for ( light = lights ; light ; light = light->next ) {
  835.  
  836.         //MrE: if the light is behind the surface
  837.         if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 )
  838.             continue;
  839.         // testing exact PTPFF
  840.         if ( exactPointToPolygon && light->type == emit_area ) {
  841.             float        factor;
  842.             float        d;
  843.             vec3_t        pushedOrigin;
  844.  
  845.             // see if the point is behind the light
  846.             d = DotProduct( origin, light->normal ) - light->dist;
  847.             if ( !light->twosided ) {
  848.                 if ( d < -1 ) {
  849.                     continue;        // point is behind light
  850.                 }
  851.             }
  852.  
  853.             // test occlusion and find light filters
  854.             // clip the line, tracing from the surface towards the light
  855.             if ( !notrace && testOcclusion ) {
  856.                 TraceLine( origin, light->origin, &trace, qfalse, tw );
  857.  
  858.                 // other light rays must not hit anything
  859.                 if ( trace.passSolid ) {
  860.                     continue;
  861.                 }
  862.             } else {
  863.                 trace.filter[0] = 1.0;
  864.                 trace.filter[1] = 1.0;
  865.                 trace.filter[2] = 1.0;
  866.             }
  867.  
  868.             // nudge the point so that it is clearly forward of the light
  869.             // so that surfaces meeting a light emiter don't get black edges
  870.             if ( d > -8 && d < 8 ) {
  871.                 VectorMA( origin, (8-d), light->normal, pushedOrigin );    
  872.             } else {
  873.                 VectorCopy( origin, pushedOrigin );
  874.             }
  875.  
  876.             // calculate the contribution
  877.             factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w );
  878.             if ( factor <= 0 ) {
  879.                 if ( light->twosided ) {
  880.                     factor = -factor;
  881.                 } else {
  882.                     continue;
  883.                 }
  884.             }
  885.             color[0] += factor * light->emitColor[0] * trace.filter[0];
  886.             color[1] += factor * light->emitColor[1] * trace.filter[1];
  887.             color[2] += factor * light->emitColor[2] * trace.filter[2];
  888.  
  889.             continue;
  890.         }
  891.  
  892.         // calculate the amount of light at this sample
  893.         if ( light->type == emit_point ) {
  894.             VectorSubtract( light->origin, origin, dir );
  895.             dist = VectorNormalize( dir, dir );
  896.             // clamp the distance to prevent super hot spots
  897.             if ( dist < 16 ) {
  898.                 dist = 16;
  899.             }
  900.             angle = DotProduct( normal, dir );
  901.             if ( light->linearLight ) {
  902.                 add = angle * light->photons * linearScale - dist;
  903.                 if ( add < 0 ) {
  904.                     add = 0;
  905.                 }
  906.             } else {
  907.                 add = light->photons / ( dist * dist ) * angle;
  908.             }
  909.         } else if ( light->type == emit_spotlight ) {
  910.             float    distByNormal;
  911.             vec3_t    pointAtDist;
  912.             float    radiusAtDist;
  913.             float    sampleRadius;
  914.             vec3_t    distToSample;
  915.             float    coneScale;
  916.  
  917.             VectorSubtract( light->origin, origin, dir );
  918.  
  919.             distByNormal = -DotProduct( dir, light->normal );
  920.             if ( distByNormal < 0 ) {
  921.                 continue;
  922.             }
  923.             VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
  924.             radiusAtDist = light->radiusByDist * distByNormal;
  925.  
  926.             VectorSubtract( origin, pointAtDist, distToSample );
  927.             sampleRadius = VectorLength( distToSample );
  928.  
  929.             if ( sampleRadius >= radiusAtDist ) {
  930.                 continue;        // outside the cone
  931.             }
  932.             if ( sampleRadius <= radiusAtDist - 32 ) {
  933.                 coneScale = 1.0;    // fully inside
  934.             } else {
  935.                 coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
  936.             }
  937.             
  938.             dist = VectorNormalize( dir, dir );
  939.             // clamp the distance to prevent super hot spots
  940.             if ( dist < 16 ) {
  941.                 dist = 16;
  942.             }
  943.             angle = DotProduct( normal, dir );
  944.             add = light->photons / ( dist * dist ) * angle * coneScale;
  945.  
  946.         } else if ( light->type == emit_area ) {
  947.             VectorSubtract( light->origin, origin, dir );
  948.             dist = VectorNormalize( dir, dir );
  949.             // clamp the distance to prevent super hot spots
  950.             if ( dist < 16 ) {
  951.                 dist = 16;
  952.             }
  953.             angle = DotProduct( normal, dir );
  954.             if ( angle <= 0 ) {
  955.                 continue;
  956.             }
  957.             angle *= -DotProduct( light->normal, dir );
  958.             if ( angle <= 0 ) {
  959.                 continue;
  960.             }
  961.  
  962.             if ( light->linearLight ) {
  963.                 add = angle * light->photons * linearScale - dist;
  964.                 if ( add < 0 ) {
  965.                     add = 0;
  966.                 }
  967.             } else {
  968.                 add = light->photons / ( dist * dist ) * angle;
  969.             }
  970.         }
  971.  
  972.         if ( add <= 1.0 ) {
  973.             continue;
  974.         }
  975.  
  976.         // clip the line, tracing from the surface towards the light
  977.         if ( !notrace && testOcclusion ) {
  978.             TraceLine( origin, light->origin, &trace, qfalse, tw );
  979.  
  980.             // other light rays must not hit anything
  981.             if ( trace.passSolid ) {
  982.                 continue;
  983.             }
  984.         } else {
  985.             trace.filter[0] = 1;
  986.             trace.filter[1] = 1;
  987.             trace.filter[2] = 1;
  988.         }
  989.         
  990.         // add the result
  991.         color[0] += add * light->color[0] * trace.filter[0];
  992.         color[1] += add * light->color[1] * trace.filter[1];
  993.         color[2] += add * light->color[2] * trace.filter[2];
  994.     }
  995.  
  996.     //
  997.     // trace directly to the sun
  998.     //
  999.     if ( testOcclusion || forceSunLight ) {
  1000.         SunToPlane( origin, normal, color, tw );
  1001.     }
  1002. }
  1003.  
  1004. /*
  1005. =============
  1006. PrintOccluded
  1007.  
  1008. For debugging
  1009. =============
  1010. */
  1011. void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE], 
  1012.                    int width, int height ) {
  1013.     int    i, j;
  1014.  
  1015.     _printf( "\n" );
  1016.  
  1017.     for ( i = 0 ; i < height ; i++ ) {
  1018.         for ( j = 0 ; j < width ; j++ ) {
  1019.             _printf("%i", (int)occluded[j][i] );
  1020.         }
  1021.         _printf( "\n" );
  1022.     }
  1023. }
  1024.  
  1025.  
  1026. /*
  1027. =============
  1028. VertexLighting
  1029.  
  1030. Vertex lighting will completely ignore occlusion, because
  1031. shadows would not be resolvable anyway.
  1032. =============
  1033. */
  1034. void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) {
  1035.     int            i, j;
  1036.     drawVert_t    *dv;
  1037.     vec3_t        sample, normal;
  1038.     float        max;
  1039.  
  1040.     VectorCopy( ds->lightmapVecs[2], normal );
  1041.  
  1042.     // generate vertex lighting
  1043.     for ( i = 0 ; i < ds->numVerts ; i++ ) {
  1044.         dv = &drawVerts[ ds->firstVert + i ];
  1045.  
  1046.         if ( ds->patchWidth ) {
  1047.             LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
  1048.         }
  1049.         else if (ds->surfaceType == MST_TRIANGLE_SOUP) {
  1050.             LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
  1051.         }
  1052.         else {
  1053.             LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw );
  1054.         }
  1055.  
  1056.         if (scale >= 0)
  1057.             VectorScale(sample, scale, sample);
  1058.         // clamp with color normalization
  1059.         max = sample[0];
  1060.         if ( sample[1] > max ) {
  1061.             max = sample[1];
  1062.         }
  1063.         if ( sample[2] > max ) {
  1064.             max = sample[2];
  1065.         }
  1066.         if ( max > 255 ) {
  1067.             VectorScale( sample, 255/max, sample );
  1068.         }
  1069.  
  1070.         // save the sample
  1071.         for ( j = 0 ; j < 3 ; j++ ) {
  1072.             if ( sample[j] > 255 ) {
  1073.                 sample[j] = 255;
  1074.             }
  1075.             dv->color[j] = sample[j];
  1076.         }
  1077.  
  1078.         // Don't bother writing alpha since it will already be set to 255,
  1079.         // plus we don't want to write over alpha generated by SetTerrainTextures
  1080.         //dv->color[3] = 255;
  1081.     }
  1082. }
  1083.  
  1084.  
  1085. /*
  1086. =================
  1087. LinearSubdivideMesh
  1088.  
  1089. For extra lighting, just midpoint one of the axis.
  1090. The edges are clamped at the original edges.
  1091. =================
  1092. */
  1093. mesh_t *LinearSubdivideMesh( mesh_t *in ) {
  1094.     int            i, j;
  1095.     mesh_t        *out;
  1096.     drawVert_t    *v1, *v2, *vout;
  1097.  
  1098.     out = malloc( sizeof( *out ) );
  1099.  
  1100.     out->width = in->width * 2;
  1101.     out->height = in->height;
  1102.     out->verts = malloc( out->width * out->height * sizeof(*out->verts) );
  1103.     for ( j = 0 ; j < in->height ; j++ ) {
  1104.         out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ];
  1105.         out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ];
  1106.         for ( i = 1 ; i < out->width - 1 ; i+= 2 ) {
  1107.             v1 = in->verts + j * in->width + (i >> 1);
  1108.             v2 = v1 + 1;
  1109.             vout = out->verts + j * out->width + i;
  1110.  
  1111.             vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0];
  1112.             vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1];
  1113.             vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2];
  1114.  
  1115.             vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0];
  1116.             vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1];
  1117.             vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2];
  1118.  
  1119.             VectorNormalize( vout->normal, vout->normal );
  1120.  
  1121.             vout++;
  1122.  
  1123.             vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0];
  1124.             vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1];
  1125.             vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2];
  1126.  
  1127.             vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0];
  1128.             vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1];
  1129.             vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2];
  1130.  
  1131.             VectorNormalize( vout->normal, vout->normal );
  1132.  
  1133.         }
  1134.     }
  1135.  
  1136.     FreeMesh( in );
  1137.  
  1138.     return out;
  1139. }
  1140.  
  1141. /*
  1142. ==============
  1143. ColorToBytes
  1144. ==============
  1145. */
  1146. void ColorToBytes( const float *color, byte *colorBytes ) {
  1147.     float    max;
  1148.     vec3_t    sample;
  1149.  
  1150.     VectorCopy( color, sample );
  1151.  
  1152.     // clamp with color normalization
  1153.     max = sample[0];
  1154.     if ( sample[1] > max ) {
  1155.         max = sample[1];
  1156.     }
  1157.     if ( sample[2] > max ) {
  1158.         max = sample[2];
  1159.     }
  1160.     if ( max > 255 ) {
  1161.         VectorScale( sample, 255/max, sample );
  1162.     }
  1163.     colorBytes[ 0 ] = sample[0];
  1164.     colorBytes[ 1 ] = sample[1];
  1165.     colorBytes[ 2 ] = sample[2];
  1166. }
  1167.  
  1168.  
  1169.  
  1170. /*
  1171. =============
  1172. TraceLtm
  1173. =============
  1174. */
  1175. void TraceLtm( int num ) {
  1176.     dsurface_t    *ds;
  1177.     int            i, j, k;
  1178.     int            x, y;
  1179.     int            position, numPositions;
  1180.     vec3_t        base, origin, normal;
  1181.     byte        occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
  1182.     vec3_t        color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
  1183.     traceWork_t    tw;
  1184.     vec3_t        average;
  1185.     int            count;
  1186.     mesh_t        srcMesh, *mesh, *subdivided;
  1187.     shaderInfo_t    *si;
  1188.     static float    nudge[2][9] = {
  1189.         { 0, -1, 0, 1, -1, 1, -1, 0, 1 },
  1190.         { 0, -1, -1, -1, 0, 0, 1, 1, 1 }
  1191.     };
  1192.     int            sampleWidth, sampleHeight, ssize;
  1193.     vec3_t        lightmapOrigin, lightmapVecs[2];
  1194.     int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH];
  1195.  
  1196.     ds = &drawSurfaces[num];
  1197.     si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
  1198.  
  1199.     // vertex-lit triangle model
  1200.     if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
  1201.         VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
  1202.         return;
  1203.     }
  1204.     
  1205.     if ( ds->lightmapNum == -1 ) {
  1206.         return;        // doesn't need lighting at all
  1207.     }
  1208.  
  1209.     if (!novertexlighting) {
  1210.         // calculate the vertex lighting for gouraud shade mode
  1211.         VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
  1212.     }
  1213.  
  1214.     if ( ds->lightmapNum < 0 ) {
  1215.         return;        // doesn't need lightmap lighting
  1216.     }
  1217.  
  1218.     si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
  1219.     ssize = samplesize;
  1220.     if (si->lightmapSampleSize)
  1221.         ssize = si->lightmapSampleSize;
  1222.  
  1223.     if (si->patchShadows)
  1224.         tw.patchshadows = qtrue;
  1225.     else
  1226.         tw.patchshadows = patchshadows;
  1227.  
  1228.     if ( ds->surfaceType == MST_PATCH ) {
  1229.         srcMesh.width = ds->patchWidth;
  1230.         srcMesh.height = ds->patchHeight;
  1231.         srcMesh.verts = drawVerts + ds->firstVert;
  1232.         mesh = SubdivideMesh( srcMesh, 8, 999 );
  1233.         PutMeshOnCurve( *mesh );
  1234.         MakeMeshNormals( *mesh );
  1235.  
  1236.         subdivided = RemoveLinearMeshColumnsRows( mesh );
  1237.         FreeMesh(mesh);
  1238.  
  1239.         mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
  1240.         if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) {
  1241.             Error( "Mesh lightmap miscount");
  1242.         }
  1243.  
  1244.         if ( extra ) {
  1245.             mesh_t    *mp;
  1246.  
  1247.             // chop it up for more light samples (leaking memory...)
  1248.             mp = mesh;//CopyMesh( mesh );
  1249.             mp = LinearSubdivideMesh( mp );
  1250.             mp = TransposeMesh( mp );
  1251.             mp = LinearSubdivideMesh( mp );
  1252.             mp = TransposeMesh( mp );
  1253.  
  1254.             mesh = mp;
  1255.         }
  1256.     } else {
  1257.         VectorCopy( ds->lightmapVecs[2], normal );
  1258.  
  1259.         if ( !extra ) {
  1260.             VectorCopy( ds->lightmapOrigin, lightmapOrigin );
  1261.             VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
  1262.             VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
  1263.         } else {
  1264.             // sample at a closer spacing for antialiasing
  1265.             VectorCopy( ds->lightmapOrigin, lightmapOrigin );
  1266.             VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] );
  1267.             VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] );
  1268.             VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin );
  1269.             VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin );
  1270.         }
  1271.     }
  1272.  
  1273.     if ( extra ) {
  1274.         sampleWidth = ds->lightmapWidth * 2;
  1275.         sampleHeight = ds->lightmapHeight * 2;
  1276.     } else {
  1277.         sampleWidth = ds->lightmapWidth;
  1278.         sampleHeight = ds->lightmapHeight;
  1279.     }
  1280.  
  1281.     memset ( color, 0, sizeof( color ) );
  1282.  
  1283.     // determine which samples are occluded
  1284.     memset ( occluded, 0, sizeof( occluded ) );
  1285.     for ( i = 0 ; i < sampleWidth ; i++ ) {
  1286.         for ( j = 0 ; j < sampleHeight ; j++ ) {
  1287.  
  1288.             if ( ds->patchWidth ) {
  1289.                 numPositions = 9;
  1290.                 VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
  1291.                 // VectorNormalize( normal, normal );
  1292.                 // push off of the curve a bit
  1293.                 VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
  1294.  
  1295.                 MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
  1296.             } else {
  1297.                 numPositions = 9;
  1298.                 for ( k = 0 ; k < 3 ; k++ ) {
  1299.                     base[k] = lightmapOrigin[k] + normal[k]
  1300.                         + i * lightmapVecs[0][k] 
  1301.                         + j * lightmapVecs[1][k];
  1302.                 }
  1303.             }
  1304.             VectorAdd( base, surfaceOrigin[ num ], base );
  1305.  
  1306.             // we may need to slightly nudge the sample point
  1307.             // if directly on a wall
  1308.             for ( position = 0 ; position < numPositions ; position++ ) {
  1309.                 // calculate lightmap sample position
  1310.                 for ( k = 0 ; k < 3 ; k++ ) {
  1311.                     origin[k] = base[k] + 
  1312.                         + ( nudge[0][position]/16 ) * lightmapVecs[0][k] 
  1313.                         + ( nudge[1][position]/16 ) * lightmapVecs[1][k];
  1314.                 }
  1315.  
  1316.                 if ( notrace ) {
  1317.                     break;
  1318.                 }
  1319.                 if ( !PointInSolid( origin ) ) {
  1320.                     break;
  1321.                 }
  1322.             }
  1323.  
  1324.             // if none of the nudges worked, this sample is occluded
  1325.             if ( position == numPositions ) {
  1326.                 occluded[i][j] = qtrue;
  1327.                 if ( numthreads == 1 ) {
  1328.                     c_occluded++;
  1329.                 }
  1330.                 continue;
  1331.             }
  1332.             
  1333.             if ( numthreads == 1 ) {
  1334.                 c_visible++;
  1335.             }
  1336.             occluded[i][j] = qfalse;
  1337.             LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw );
  1338.         }
  1339.     }
  1340.  
  1341.     if ( dump ) {
  1342.         PrintOccluded( occluded, sampleWidth, sampleHeight );
  1343.     }
  1344.  
  1345.     // calculate average values for occluded samples
  1346.     for ( i = 0 ; i < sampleWidth ; i++ ) {
  1347.         for ( j = 0 ; j < sampleHeight ; j++ ) {
  1348.             if ( !occluded[i][j] ) {
  1349.                 continue;
  1350.             }
  1351.             // scan all surrounding samples
  1352.             count = 0;
  1353.             VectorClear( average );
  1354.             for ( x = -1 ; x <= 1; x++ ) {
  1355.                 for ( y = -1 ; y <= 1 ; y++ ) {
  1356.                     if ( i + x < 0 || i + x >= sampleWidth ) {
  1357.                         continue;
  1358.                     }
  1359.                     if ( j + y < 0 || j + y >= sampleHeight ) {
  1360.                         continue;
  1361.                     }
  1362.                     if ( occluded[i+x][j+y] ) {
  1363.                         continue;
  1364.                     }
  1365.                     count++;
  1366.                     VectorAdd( color[i+x][j+y], average, average );
  1367.                 }
  1368.             }
  1369.             if ( count ) {
  1370.                 VectorScale( average, 1.0/count, color[i][j] );
  1371.             }
  1372.         }
  1373.     }
  1374.  
  1375.     // average together the values if we are extra sampling
  1376.     if ( ds->lightmapWidth != sampleWidth ) {
  1377.         for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
  1378.             for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
  1379.                 for ( k = 0 ; k < 3 ; k++ ) {
  1380.                     float        value, coverage;
  1381.  
  1382.                     value = color[i*2][j*2][k] + color[i*2][j*2+1][k] +
  1383.                         color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k];
  1384.                     coverage = 4;
  1385.                     if ( extraWide ) {
  1386.                         // wider than box filter
  1387.                         if ( i > 0 ) {
  1388.                             value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k];
  1389.                             value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k];
  1390.                             coverage += 4;
  1391.                         }
  1392.                         if ( i < ds->lightmapWidth - 1 ) {
  1393.                             value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k];
  1394.                             value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k];
  1395.                             coverage += 4;
  1396.                         }
  1397.                         if ( j > 0 ) {
  1398.                             value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k];
  1399.                             value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k];
  1400.                             coverage += 4;
  1401.                         }
  1402.                         if ( j < ds->lightmapHeight - 1 ) {
  1403.                             value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k];
  1404.                             value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k];
  1405.                             coverage += 2;
  1406.                         }
  1407.                     }
  1408.  
  1409.                     color[i][j][k] = value / coverage;
  1410.                 }
  1411.             }
  1412.         }
  1413.     }
  1414.  
  1415.     // optionally create a debugging border around the lightmap
  1416.     if ( lightmapBorder ) {
  1417.         for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
  1418.             color[i][0][0] = 255;
  1419.             color[i][0][1] = 0;
  1420.             color[i][0][2] = 0;
  1421.  
  1422.             color[i][ds->lightmapHeight-1][0] = 255;
  1423.             color[i][ds->lightmapHeight-1][1] = 0;
  1424.             color[i][ds->lightmapHeight-1][2] = 0;
  1425.         }
  1426.         for ( i = 0 ; i < ds->lightmapHeight ; i++ ) {
  1427.             color[0][i][0] = 255;
  1428.             color[0][i][1] = 0;
  1429.             color[0][i][2] = 0;
  1430.  
  1431.             color[ds->lightmapWidth-1][i][0] = 255;
  1432.             color[ds->lightmapWidth-1][i][1] = 0;
  1433.             color[ds->lightmapWidth-1][i][2] = 0;
  1434.         }
  1435.     }
  1436.  
  1437.     // clamp the colors to bytes and store off
  1438.     for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
  1439.         for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
  1440.             k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j) 
  1441.                 * LIGHTMAP_WIDTH + ds->lightmapX + i;
  1442.  
  1443.             ColorToBytes( color[i][j], lightBytes + k*3 );
  1444.         }
  1445.     }
  1446.  
  1447.     if (ds->surfaceType == MST_PATCH)
  1448.     {
  1449.         FreeMesh(mesh);
  1450.     }
  1451. }
  1452.  
  1453.  
  1454. //=============================================================================
  1455.  
  1456. vec3_t    gridMins;
  1457. vec3_t    gridSize = { 64, 64, 128 };
  1458. int        gridBounds[3];
  1459.  
  1460.  
  1461. /*
  1462. ========================
  1463. LightContributionToPoint
  1464. ========================
  1465. */
  1466. qboolean LightContributionToPoint( const light_t *light, const vec3_t origin,
  1467.                                   vec3_t color, traceWork_t *tw ) {
  1468.     trace_t        trace;
  1469.     float        add;
  1470.  
  1471.     add = 0;
  1472.  
  1473.     VectorClear( color );
  1474.  
  1475.     // testing exact PTPFF
  1476.     if ( exactPointToPolygon && light->type == emit_area ) {
  1477.         float        factor;
  1478.         float        d;
  1479.         vec3_t        normal;
  1480.  
  1481.         // see if the point is behind the light
  1482.         d = DotProduct( origin, light->normal ) - light->dist;
  1483.         if ( !light->twosided ) {
  1484.             if ( d < 1 ) {
  1485.                 return qfalse;        // point is behind light
  1486.             }
  1487.         }
  1488.  
  1489.         // test occlusion
  1490.         // clip the line, tracing from the surface towards the light
  1491.         TraceLine( origin, light->origin, &trace, qfalse, tw );
  1492.         if ( trace.passSolid ) {
  1493.             return qfalse;
  1494.         }
  1495.  
  1496.         // calculate the contribution
  1497.         VectorSubtract( light->origin, origin, normal );
  1498.         if ( VectorNormalize( normal, normal ) == 0 ) {
  1499.             return qfalse;
  1500.         }
  1501.         factor = PointToPolygonFormFactor( origin, normal, light->w );
  1502.         if ( factor <= 0 ) {
  1503.             if ( light->twosided ) {
  1504.                 factor = -factor;
  1505.             } else {
  1506.                 return qfalse;
  1507.             }
  1508.         }
  1509.         VectorScale( light->emitColor, factor, color );
  1510.         return qtrue;
  1511.     }
  1512.  
  1513.     // calculate the amount of light at this sample
  1514.     if ( light->type == emit_point || light->type == emit_spotlight ) {
  1515.         vec3_t        dir;
  1516.         float        dist;
  1517.  
  1518.         VectorSubtract( light->origin, origin, dir );
  1519.         dist = VectorLength( dir );
  1520.         // clamp the distance to prevent super hot spots
  1521.         if ( dist < 16 ) {
  1522.             dist = 16;
  1523.         }
  1524.         if ( light->linearLight ) {
  1525.             add = light->photons * linearScale - dist;
  1526.             if ( add < 0 ) {
  1527.                 add = 0;
  1528.             }
  1529.         } else {
  1530.             add = light->photons / ( dist * dist );
  1531.         }
  1532.     } else {
  1533.         return qfalse;
  1534.     }
  1535.  
  1536.     if ( add <= 1.0 ) {
  1537.         return qfalse;
  1538.     }
  1539.  
  1540.     // clip the line, tracing from the surface towards the light
  1541.     TraceLine( origin, light->origin, &trace, qfalse, tw );
  1542.  
  1543.     // other light rays must not hit anything
  1544.     if ( trace.passSolid ) {
  1545.         return qfalse;
  1546.     }
  1547.  
  1548.     // add the result
  1549.     color[0] = add * light->color[0];
  1550.     color[1] = add * light->color[1];
  1551.     color[2] = add * light->color[2];
  1552.  
  1553.     return qtrue;
  1554. }
  1555.  
  1556. typedef struct {
  1557.     vec3_t        dir;
  1558.     vec3_t        color;
  1559. } contribution_t;
  1560.  
  1561. /*
  1562. =============
  1563. TraceGrid
  1564.  
  1565. Grid samples are foe quickly determining the lighting
  1566. of dynamically placed entities in the world
  1567. =============
  1568. */
  1569. #define    MAX_CONTRIBUTIONS    1024
  1570. void TraceGrid( int num ) {
  1571.     int            x, y, z;
  1572.     vec3_t        origin;
  1573.     light_t        *light;
  1574.     vec3_t        color;
  1575.     int            mod;
  1576.     vec3_t        directedColor;
  1577.     vec3_t        summedDir;
  1578.     contribution_t    contributions[MAX_CONTRIBUTIONS];
  1579.     int            numCon;
  1580.     int            i;
  1581.     traceWork_t    tw;
  1582.     float        addSize;
  1583.  
  1584.     mod = num;
  1585.     z = mod / ( gridBounds[0] * gridBounds[1] );
  1586.     mod -= z * ( gridBounds[0] * gridBounds[1] );
  1587.  
  1588.     y = mod / gridBounds[0];
  1589.     mod -= y * gridBounds[0];
  1590.  
  1591.     x = mod;
  1592.  
  1593.     origin[0] = gridMins[0] + x * gridSize[0];
  1594.     origin[1] = gridMins[1] + y * gridSize[1];
  1595.     origin[2] = gridMins[2] + z * gridSize[2];
  1596.  
  1597.     if ( PointInSolid( origin ) ) {
  1598.         vec3_t    baseOrigin;
  1599.         int        step;
  1600.  
  1601.         VectorCopy( origin, baseOrigin );
  1602.  
  1603.         // try to nudge the origin around to find a valid point
  1604.         for ( step = 9 ; step <= 18 ; step += 9 ) {
  1605.             for ( i = 0 ; i < 8 ; i++ ) {
  1606.                 VectorCopy( baseOrigin, origin );
  1607.                 if ( i & 1 ) {
  1608.                     origin[0] += step;
  1609.                 } else {
  1610.                     origin[0] -= step;
  1611.                 }
  1612.                 if ( i & 2 ) {
  1613.                     origin[1] += step;
  1614.                 } else {
  1615.                     origin[1] -= step;
  1616.                 }
  1617.                 if ( i & 4 ) {
  1618.                     origin[2] += step;
  1619.                 } else {
  1620.                     origin[2] -= step;
  1621.                 }
  1622.  
  1623.                 if ( !PointInSolid( origin ) ) {
  1624.                     break;
  1625.                 }
  1626.             }
  1627.             if ( i != 8 ) {
  1628.                 break;
  1629.             }
  1630.         }
  1631.         if ( step > 18 ) {
  1632.             // can't find a valid point at all
  1633.             for ( i = 0 ; i < 8 ; i++ ) {
  1634.                 gridData[ num*8 + i ] = 0;
  1635.             }
  1636.             return;
  1637.         }
  1638.     }
  1639.  
  1640.     VectorClear( summedDir );
  1641.  
  1642.     // trace to all the lights
  1643.  
  1644.     // find the major light direction, and divide the
  1645.     // total light between that along the direction and
  1646.     // the remaining in the ambient 
  1647.     numCon = 0;
  1648.     for ( light = lights ; light ; light = light->next ) {
  1649.         vec3_t        add;
  1650.         vec3_t        dir;
  1651.         float        addSize;
  1652.  
  1653.         if ( !LightContributionToPoint( light, origin, add, &tw ) ) {
  1654.             continue;
  1655.         }
  1656.  
  1657.         VectorSubtract( light->origin, origin, dir );
  1658.         VectorNormalize( dir, dir );
  1659.  
  1660.         VectorCopy( add, contributions[numCon].color );
  1661.         VectorCopy( dir, contributions[numCon].dir );
  1662.         numCon++;
  1663.  
  1664.         addSize = VectorLength( add );
  1665.         VectorMA( summedDir, addSize, dir, summedDir );
  1666.  
  1667.         if ( numCon == MAX_CONTRIBUTIONS-1 ) {
  1668.             break;
  1669.         }
  1670.     }
  1671.  
  1672.     //
  1673.     // trace directly to the sun
  1674.     //
  1675.     SunToPoint( origin, &tw, color );
  1676.     addSize = VectorLength( color );
  1677.     if ( addSize > 0 ) {
  1678.         VectorCopy( color, contributions[numCon].color );
  1679.         VectorCopy( sunDirection, contributions[numCon].dir );
  1680.         VectorMA( summedDir, addSize, sunDirection, summedDir );
  1681.         numCon++;
  1682.     }
  1683.  
  1684.  
  1685.     // now that we have identified the primary light direction,
  1686.     // go back and seperate all the light into directed and ambient
  1687.     VectorNormalize( summedDir, summedDir );
  1688.     VectorCopy( ambientColor, color );
  1689.     VectorClear( directedColor );
  1690.  
  1691.     for ( i = 0 ; i < numCon ; i++ ) {
  1692.         float    d;
  1693.  
  1694.         d = DotProduct( contributions[i].dir, summedDir );
  1695.         if ( d < 0 ) {
  1696.             d = 0;
  1697.         }
  1698.  
  1699.         VectorMA( directedColor, d, contributions[i].color, directedColor );
  1700.  
  1701.         // the ambient light will be at 1/4 the value of directed light
  1702.         d = 0.25 * ( 1.0 - d );
  1703.         VectorMA( color, d, contributions[i].color, color );
  1704.     }
  1705.  
  1706.     // now do some fudging to keep the ambient from being too low
  1707.     VectorMA( color, 0.25, directedColor, color );
  1708.  
  1709.     //
  1710.     // save the resulting value out
  1711.     //
  1712.     ColorToBytes( color, gridData + num*8 );
  1713.     ColorToBytes( directedColor, gridData + num*8 + 3 );
  1714.  
  1715.     VectorNormalize( summedDir, summedDir );
  1716.     NormalToLatLong( summedDir, gridData + num*8 + 6);
  1717. }
  1718.  
  1719.  
  1720. /*
  1721. =============
  1722. SetupGrid
  1723. =============
  1724. */
  1725. void SetupGrid( void ) {
  1726.     int        i;
  1727.     vec3_t    maxs;
  1728.  
  1729.     for ( i = 0 ; i < 3 ; i++ ) {
  1730.         gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] );
  1731.         maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] );
  1732.         gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1;
  1733.     }
  1734.  
  1735.     numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2];
  1736.     if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID)
  1737.         Error("MAX_MAP_LIGHTGRID");
  1738.     qprintf( "%5i gridPoints\n", numGridPoints );
  1739. }
  1740.  
  1741. //=============================================================================
  1742.  
  1743. /*
  1744. =============
  1745. RemoveLightsInSolid
  1746. =============
  1747. */
  1748. void RemoveLightsInSolid(void)
  1749. {
  1750.     light_t *light, *prev;
  1751.     int numsolid = 0;
  1752.  
  1753.     prev = NULL;
  1754.     for ( light = lights ; light ;  ) {
  1755.         if (PointInSolid(light->origin))
  1756.         {
  1757.             if (prev) prev->next = light->next;
  1758.             else lights = light->next;
  1759.             if (light->w)
  1760.                 FreeWinding(light->w);
  1761.             free(light);
  1762.             numsolid++;
  1763.             if (prev)
  1764.                 light = prev->next;
  1765.             else
  1766.                 light = lights;
  1767.         }
  1768.         else
  1769.         {
  1770.             prev = light;
  1771.             light = light->next;
  1772.         }
  1773.     }
  1774.     _printf (" %7i lights in solid\n", numsolid);
  1775. }
  1776.  
  1777. /*
  1778. =============
  1779. LightWorld
  1780. =============
  1781. */
  1782. void LightWorld (void) {
  1783.     float        f;
  1784.  
  1785.     // determine the number of grid points
  1786.     SetupGrid();
  1787.  
  1788.     // find the optional world ambient
  1789.     GetVectorForKey( &entities[0], "_color", ambientColor );
  1790.     f = FloatForKey( &entities[0], "ambient" );
  1791.     VectorScale( ambientColor, f, ambientColor );
  1792.  
  1793.     // create lights out of patches and lights
  1794.     qprintf ("--- CreateLights ---\n");
  1795.     CreateEntityLights ();
  1796.     qprintf ("%i point lights\n", numPointLights);
  1797.     qprintf ("%i area lights\n", numAreaLights);
  1798.  
  1799.     if (!nogridlighting) {
  1800.         qprintf ("--- TraceGrid ---\n");
  1801.         RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
  1802.         qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1],
  1803.             gridBounds[2], numGridPoints);
  1804.     }
  1805.  
  1806.     qprintf ("--- TraceLtm ---\n");
  1807.     RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm );
  1808.     qprintf( "%5i visible samples\n", c_visible );
  1809.     qprintf( "%5i occluded samples\n", c_occluded );
  1810. }
  1811.  
  1812. /*
  1813. ========
  1814. CreateFilters
  1815.  
  1816. EXPERIMENTAL, UNUSED
  1817.  
  1818. Look for transparent light filter surfaces.
  1819.  
  1820. This will only work for flat 3*3 patches that exactly hold one copy of the texture.
  1821. ========
  1822. */
  1823. #define    PLANAR_PATCH_EPSILON    0.1
  1824. void CreateFilters( void ) {
  1825.     int                i;
  1826.     filter_t        *f;
  1827.     dsurface_t        *ds;
  1828.     shaderInfo_t    *si;
  1829.     drawVert_t        *v1, *v2, *v3;
  1830.     vec3_t            d1, d2;
  1831.     int                vertNum;
  1832.  
  1833.     numFilters = 0;
  1834.  
  1835.     return;
  1836.  
  1837.     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
  1838.         ds = &drawSurfaces[i];
  1839.         if ( !ds->patchWidth ) {
  1840.             continue;
  1841.         }
  1842.         si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader );
  1843. /*
  1844.         if ( !(si->surfaceFlags & SURF_LIGHTFILTER) ) {
  1845.             continue;
  1846.         }
  1847. */
  1848.  
  1849.         // we have a filter patch
  1850.         v1 = &drawVerts[ ds->firstVert ];
  1851.  
  1852.         if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) {
  1853.             _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n",
  1854.                 v1->xyz[0], v1->xyz[1], v1->xyz[2] );
  1855.             continue;
  1856.         }
  1857.  
  1858.         if ( numFilters == MAX_FILTERS ) {
  1859.             Error( "MAX_FILTERS" );
  1860.         }
  1861.         f = &filters[ numFilters ];
  1862.         numFilters++;
  1863.  
  1864.         v2 = &drawVerts[ ds->firstVert + 2 ];
  1865.         v3 = &drawVerts[ ds->firstVert + 6 ];
  1866.  
  1867.         VectorSubtract( v2->xyz, v1->xyz, d1 );
  1868.         VectorSubtract( v3->xyz, v1->xyz, d2 );
  1869.         VectorNormalize( d1, d1 );
  1870.         VectorNormalize( d2, d2 );
  1871.         CrossProduct( d1, d2, f->plane );
  1872.         f->plane[3] = DotProduct( v1->xyz, f->plane );
  1873.  
  1874.         // make sure all the control points are on the plane
  1875.         for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) {
  1876.             float    d;
  1877.  
  1878.             d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3];
  1879.             if ( fabs( d ) > PLANAR_PATCH_EPSILON ) {
  1880.                 break;
  1881.             }
  1882.         }
  1883.         if ( vertNum != ds->numVerts ) {
  1884.             numFilters--;
  1885.             _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n",
  1886.                 v1->xyz[0], v1->xyz[1], v1->xyz[2] );
  1887.             continue;
  1888.         }
  1889.     }
  1890.  
  1891.     f = &filters[0];
  1892.     numFilters = 1;
  1893.  
  1894.     f->plane[0] = 1;
  1895.     f->plane[1] = 0;
  1896.     f->plane[2] = 0;
  1897.     f->plane[3] = 448;
  1898.  
  1899.     f->origin[0] = 448;
  1900.     f->origin[1] = 192;
  1901.     f->origin[2] = 0;
  1902.  
  1903.     f->vectors[0][0] = 0;
  1904.     f->vectors[0][1] = -1.0 / 128;
  1905.     f->vectors[0][2] = 0;
  1906.  
  1907.     f->vectors[1][0] = 0;
  1908.     f->vectors[1][1] = 0;
  1909.     f->vectors[1][2] = 1.0 / 128;
  1910.  
  1911.     f->si = ShaderInfoForShader( "textures/hell/blocks11ct" );
  1912. }
  1913.  
  1914. /*
  1915. =============
  1916. VertexLightingThread
  1917. =============
  1918. */
  1919. void VertexLightingThread(int num) {
  1920.     dsurface_t    *ds;
  1921.     traceWork_t    tw;
  1922.     shaderInfo_t *si;
  1923.  
  1924.     ds = &drawSurfaces[num];
  1925.  
  1926.     // vertex-lit triangle model
  1927.     if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
  1928.         return;
  1929.     }
  1930.  
  1931.     if (novertexlighting)
  1932.         return;
  1933.  
  1934.     if ( ds->lightmapNum == -1 ) {
  1935.         return;    // doesn't need lighting at all
  1936.     }
  1937.  
  1938.     si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
  1939.  
  1940.     // calculate the vertex lighting for gouraud shade mode
  1941.     VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
  1942. }
  1943.  
  1944. /*
  1945. =============
  1946. TriSoupLightingThread
  1947. =============
  1948. */
  1949. void TriSoupLightingThread(int num) {
  1950.     dsurface_t    *ds;
  1951.     traceWork_t    tw;
  1952.     shaderInfo_t *si;
  1953.  
  1954.     ds = &drawSurfaces[num];
  1955.     si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
  1956.  
  1957.     // vertex-lit triangle model
  1958.     if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
  1959.         VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
  1960.     }
  1961. }
  1962.  
  1963. /*
  1964. =============
  1965. GridAndVertexLighting
  1966. =============
  1967. */
  1968. void GridAndVertexLighting(void) {
  1969.     SetupGrid();
  1970.  
  1971.     FindSkyBrushes();
  1972.     CreateFilters();
  1973.     InitTrace();
  1974.     CreateEntityLights ();
  1975.     CreateSurfaceLights();
  1976.  
  1977.     if (!nogridlighting) {
  1978.         _printf ("--- TraceGrid ---\n");
  1979.         RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
  1980.     }
  1981.  
  1982.     if (!novertexlighting) {
  1983.         _printf ("--- Vertex Lighting ---\n");
  1984.         RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread );
  1985.     }
  1986.  
  1987.     _printf("--- Model Lighting ---\n");
  1988.     RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread );
  1989. }
  1990.  
  1991. /*
  1992. ========
  1993. LightMain
  1994.  
  1995. ========
  1996. */
  1997. int LightMain (int argc, char **argv) {
  1998.     int            i;
  1999.     double        start, end;
  2000.     const char    *value;
  2001.  
  2002.     _printf ("----- Lighting ----\n");
  2003.  
  2004.     verbose = qfalse;
  2005.  
  2006.     for (i=1 ; i<argc ; i++) {
  2007.         if (!strcmp(argv[i],"-tempname"))
  2008.     {
  2009.       i++;
  2010.     } else if (!strcmp(argv[i],"-v")) {
  2011.             verbose = qtrue;
  2012.         } else if (!strcmp(argv[i],"-threads")) {
  2013.             numthreads = atoi (argv[i+1]);
  2014.             i++;
  2015.         } else if (!strcmp(argv[i],"-area")) {
  2016.             areaScale *= atof(argv[i+1]);
  2017.             _printf ("area light scaling at %f\n", areaScale);
  2018.             i++;
  2019.         } else if (!strcmp(argv[i],"-point")) {
  2020.             pointScale *= atof(argv[i+1]);
  2021.             _printf ("point light scaling at %f\n", pointScale);
  2022.             i++;
  2023.         } else if (!strcmp(argv[i],"-notrace")) {
  2024.             notrace = qtrue;
  2025.             _printf ("No occlusion tracing\n");
  2026.         } else if (!strcmp(argv[i],"-patchshadows")) {
  2027.             patchshadows = qtrue;
  2028.             _printf ("Patch shadow casting enabled\n");
  2029.         } else if (!strcmp(argv[i],"-extra")) {
  2030.             extra = qtrue;
  2031.             _printf ("Extra detail tracing\n");
  2032.         } else if (!strcmp(argv[i],"-extrawide")) {
  2033.             extra = qtrue;
  2034.             extraWide = qtrue;
  2035.             _printf ("Extra wide detail tracing\n");
  2036.         } else if (!strcmp(argv[i], "-samplesize")) {
  2037.             samplesize = atoi(argv[i+1]);
  2038.             if (samplesize < 1) samplesize = 1;
  2039.             i++;
  2040.             _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
  2041.         } else if (!strcmp(argv[i], "-novertex")) {
  2042.             novertexlighting = qtrue;
  2043.             _printf("no vertex lighting = true\n");
  2044.         } else if (!strcmp(argv[i], "-nogrid")) {
  2045.             nogridlighting = qtrue;
  2046.             _printf("no grid lighting = true\n");
  2047.         } else if (!strcmp(argv[i],"-border")) {
  2048.             lightmapBorder = qtrue;
  2049.             _printf ("Adding debug border to lightmaps\n");
  2050.         } else if (!strcmp(argv[i],"-nosurf")) {
  2051.             noSurfaces = qtrue;
  2052.             _printf ("Not tracing against surfaces\n" );
  2053.         } else if (!strcmp(argv[i],"-dump")) {
  2054.             dump = qtrue;
  2055.             _printf ("Dumping occlusion maps\n");
  2056.         } else {
  2057.             break;
  2058.         }
  2059.     }
  2060.  
  2061.     ThreadSetDefault ();
  2062.  
  2063.     if (i != argc - 1) {
  2064.         _printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n"
  2065.                 "\n"
  2066.                 "Switches:\n"
  2067.                 "   v              = verbose output\n"
  2068.                 "   threads <X>    = set number of threads to X\n"
  2069.                 "   area <V>       = set the area light scale to V\n"
  2070.                 "   point <W>      = set the point light scale to W\n"
  2071.                 "   notrace        = don't cast any shadows\n"
  2072.                 "   extra          = enable super sampling for anti-aliasing\n"
  2073.                 "   extrawide      = same as extra but smoothen more\n"
  2074.                 "   nogrid         = don't calculate light grid for dynamic model lighting\n"
  2075.                 "   novertex       = don't calculate vertex lighting\n"
  2076.                 "   samplesize <N> = set the lightmap pixel size to NxN units\n");
  2077.         exit(0);
  2078.     }
  2079.  
  2080.     start = I_FloatTime ();
  2081.  
  2082.     SetQdirFromPath (argv[i]);    
  2083.  
  2084. #ifdef _WIN32
  2085.     InitPakFile(gamedir, NULL);
  2086. #endif
  2087.  
  2088.     strcpy (source, ExpandArg(argv[i]));
  2089.     StripExtension (source);
  2090.     DefaultExtension (source, ".bsp");
  2091.  
  2092.     LoadShaderInfo();
  2093.  
  2094.     _printf ("reading %s\n", source);
  2095.  
  2096.     LoadBSPFile (source);
  2097.  
  2098.     FindSkyBrushes();
  2099.  
  2100.     ParseEntities();
  2101.  
  2102.     value = ValueForKey( &entities[0], "gridsize" );
  2103.     if (strlen(value)) {
  2104.         sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
  2105.         _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
  2106.     }
  2107.  
  2108.     CreateFilters();
  2109.  
  2110.     InitTrace();
  2111.  
  2112.     SetEntityOrigins();
  2113.  
  2114.     CountLightmaps();
  2115.  
  2116.     CreateSurfaceLights();
  2117.  
  2118.     LightWorld();
  2119.  
  2120.     _printf ("writing %s\n", source);
  2121.     WriteBSPFile (source);
  2122.  
  2123.     end = I_FloatTime ();
  2124.     _printf ("%5.0f seconds elapsed\n", end-start);
  2125.     
  2126.     return 0;
  2127. }
  2128.  
  2129.